function hfile = subsasgn(hfile, S, V)
% BVQXfile::subsasgn  - overloaded method
%
% used to update properties in objects
%
% vmr.DimX = 512;
%
% if the Update method (vmr_Update in this case) is available,
% it will be called, unless the update function has been disabled
% with BVQXfile(0, 'updatedisable', 'vmr');

% Version:  v0.7f
% Build:    8110521
% Date:     Nov-05 2008, 9:00 PM CET
% Author:   Jochen Weber, SCAN Unit, Columbia University, NYC, NY, USA
% URL/Info: http://wiki.brainvoyager.com/BVQXtools

% global storage and config
global bvqxclup;
global bvqxcont;
global bvqxfile_config;

% persistent methods
persistent bvqxfile_methods;
if isempty(bvqxfile_methods)
    bvqxfile_methods = BVQXfile(0, 'methods');
end

% class check
if nargin > 2 && ...
    ~isa(hfile, 'BVQXfile')
    try
        hfile = builtin('subsasgn', hfile, S, V);
    catch
        rethrow(lasterror);
    end
    return;
end

% argument check
if nargin < 3 || ...
   isempty(S)
    error( ...
        'BVQXfile:BadSubsAsgn', ...
        'S struct must not be empty.' ...
    );
end

% get struct version and good fieldnames
sfile = struct(hfile);

% decide on kind of subscripting, first struct-like notation
slen  = length(S);
stype = S(1).type;
ssubs = S(1).subs;
switch stype, case {'.'}

    % check for subscript type
    if ~ischar(ssubs) || isempty(ssubs)
        error( ...
            'BVQXfile:BadSubsAsgn', ...
            'Struct notation needs a non-empty char property.' ...
        );
    end

    % only works for singular object
    if numel(hfile) ~= 1 || ...
        hfile.L == 1
        error( ...
            'BVQXfile:InvalidObjectSize', ...
            'Struct notation only works on singular non-ROOT objects.' ...
        );
    end
    
    % get index
    ifile = find(bvqxclup == hfile.L);
    if isempty(ifile)
        error( ...
            'BVQXfile:InvalidObject', ...
            'Object removed from memory.' ...
        );
    end

    % make content linear
    ssubs = ssubs(:)';

    % only allow already existing fields
    fgood = fieldnames(bvqxcont(ifile).C);
    ffound = strcmpi(ssubs, fgood);
    if ~any(ffound)
        error( ...
            'BVQXfile:InvalidProperty', ...
            'Non-existing property for this BVQXfile type.' ...
        );
    end

    % get correct case fieldname
    ffound = find(ffound);
    ssubs = fgood{ffound(1)};

    % set complete property
    if slen == 1

        % try setting value
        try
            oV = bvqxcont(ifile).C.(ssubs);
            bvqxcont(ifile).C.(ssubs) = V;
        catch
            rethrow(lasterror);
        end

    % set sub value
    else

        % try getting, altering and re-setting value
        try
            oV = bvqxcont(ifile).C.(ssubs);
            bvqxcont(ifile).C.(ssubs) = subsasgn(oV, S(2:end), V);
        catch
            rethrow(lasterror);
        end
    end
    
    % perform obj_Update call ?
    ftype = lower(bvqxcont(ifile).S.Extensions{1});
    if isfield(bvqxfile_methods, ftype) && ...
        isfield(bvqxfile_methods.(ftype), 'update') && ...
        bvqxfile_config.update.(ftype)
        try
            eval([bvqxfile_methods.(ftype).update{1} '(hfile, ssubs, S, oV);']);
        catch
            error( ...
                'BVQXfile:ObjectUpdateError', ...
                'Error performing object update: ''%s''.', ...
                lasterr ...
            );
        end
    end

% indexing requested
case {'()'}

    % we need non-empty cell subscript
    if ~iscell(ssubs) || isempty(ssubs)
        error( ...
            'BVQXfile:BadSubsRef', ...
            'Can''t index into BVQXfile matrix.' ...
        );
    end

    % try to retrieve subscripted matrix
    try
        subset = subsref(sfile, S(1));
    catch
        error( ...
            'BVQXfile:BadSubsRef', ...
            'Invalid subscript (%s). Dynamic growing unavailable.', ...
            lasterr ...
        );
    end

    % no further subsasgn requested
    if slen == 1
        if ~isBVQXfile(V, true)
            error( ...
                'BVQXfile:BadSubsAsgnValue', ...
                'Class mismatch error or invalid object.' ...
            );
        end

        % try to assign new objects into matrix
        try
            sfile = subsasgn(sfile, S(1), struct(V));
            hfile = BVQXfile(0, 'makeobject', sfile);
        catch
            error( ...
                'BVQXfile:BadSubsAsgnIndex', ...
                'Couldn''t assign partial object matrix (%s).', ...
                lasterr ...
            );
        end

        % unwind stack
        if bvqxfile_config.unwindstack
            BVQXfile(0, 'unwindstack');
        end
        return;
    end

    % further indexing only allowed for single object
    if numel(subset) ~= 1 || ...
        subset.L == 1
        error( ...
            'BVQXfile:InvalidObjectSize', ...
            'Subscripting only works for singular, non-ROOT objects.' ...
        );
    end

    % try subsasgn
    try
        subsasgn(BVQXfile(0, 'makeobject', subset), S(2:end), V);
    catch
        error( ...
            'BVQXfile:BadSubsAsgnSubs', ...
            'Error passing subsasgn to object (%s).', ...
            lasterr ...
        );
    end

% generally wrong
otherwise

    error( ...
        'BVQXfile:BadSubsAsgn', ...
        'Only struct notation allowed to set values.' ...
    );
end

% unwind stack
if bvqxfile_config.unwindstack
    BVQXfile(0, 'unwindstack');
end
